#ifndef READCCMIO_HPP
#define READCCMIO_HPP

#ifndef IS_BUILDING_MB
#error "ReadCCMIO.hpp isn't supposed to be included into an application"
#endif

#include <vector>
#include <set>
#include <map>
#include <string>

#include "moab/Forward.hpp"
#include "moab/Range.hpp"
#include "moab/ExoIIInterface.hpp"
#include "moab/ReaderIface.hpp"
//#include "moab/TupleList.hpp"
#include "ccmio.h"

namespace moab
{

#undef READCCMIO_USE_TUPLE_LIST

class ReadUtilIface;

class ReadCCMIO : public ReaderIface
{

  public:
    typedef std::map< int, std::vector< EntityHandle > > TupleList;
    typedef std::map< int, std::vector< int > > SenseList;

    //! Constructor
    ReadCCMIO( Interface* impl );

    //! Destructor
    virtual ~ReadCCMIO();

    static ReaderIface* factory( Interface* );

    ErrorCode load_file( const char* file_name,
                         const EntityHandle* file_set,
                         const FileOptions& opts,
                         const SubsetList* subset_list = 0,
                         const Tag* file_id_tag        = 0 );

  private:
    ErrorCode read_processor( CCMIOID rootID,
                              CCMIOID problemID,
                              CCMIOID processorID,
                              CCMIOID verticesID,
                              CCMIOID topologyID,
                              CCMIOSize_t proc,
                              Range* new_ents );

    ErrorCode read_cells( CCMIOSize_t proc,
                          CCMIOID processorID,
                          CCMIOID verticesID,
                          CCMIOID topologyID,
                          TupleList& vert_map,
                          Range* new_cells );

    ErrorCode construct_cells( TupleList& face_map,
#ifndef READCCMIO_USE_TUPLE_LIST
                               SenseList& sense_map,
#endif
                               TupleList& vert_map,
                               std::map< int, int >& cell_topo_types,
                               std::vector< EntityHandle >& new_cells );

    ErrorCode ccmio_to_moab_type( int ccm_type, EntityType& moab_type, bool& has_mid_nodes );

    ErrorCode create_cell_from_faces( std::vector< EntityHandle >& facehs,
                                      std::vector< int >& senses,
                                      EntityType this_type,
                                      bool has_mid_nodes,
                                      EntityHandle& cell );

    ErrorCode read_gids_and_types( CCMIOID problemID, CCMIOID topologyID, std::vector< EntityHandle >& cells );

    ErrorCode read_all_faces( CCMIOID topologyID,
                              TupleList& vert_map,
                              TupleList& face_map
#ifndef READCCMIO_USE_TUPLE_LIST
                              ,
                              SenseList& sense_map
#endif
                              ,
                              Range* new_faces );

    ErrorCode read_faces( CCMIOID faceID,
                          CCMIOEntity bdy_or_int,
                          TupleList& vert_map,
                          TupleList& face_map
#ifndef READCCMIO_USE_TUPLE_LIST
                          ,
                          SenseList& sense_map
#endif
                          ,
                          Range* new_faces );

    ErrorCode make_faces( int* farray, TupleList& vert_map, std::vector< EntityHandle >& new_faces, int num_faces );

    ErrorCode read_vertices( CCMIOSize_t proc,
                             CCMIOID processorID,
                             CCMIOID verticesID,
                             CCMIOID topologyID,
                             Range* verts,
                             TupleList& vert_map );

    ErrorCode get_processors( CCMIOID stateID,
                              CCMIOID& processorID,
                              CCMIOID& verticesID,
                              CCMIOID& topologyID,
                              CCMIOID& solutionID,
                              std::vector< CCMIOSize_t >& procs,
                              bool& has_solution );

    ErrorCode get_state( CCMIOID rootID, CCMIOID& problemID, CCMIOID& stateID );

    ErrorCode read_tag_values( const char* file_name,
                               const char* tag_name,
                               const FileOptions& opts,
                               std::vector< int >& tag_values_out,
                               const SubsetList* subset_list = 0 );

    ErrorCode load_matset_data( CCMIOID problemID );

    ErrorCode load_neuset_data( CCMIOID problemID );

    ErrorCode load_metadata( CCMIOID rootID,
                             CCMIOID problemID,
                             CCMIOID stateID,
                             CCMIOID processorID,
                             const EntityHandle* file_set );

    ErrorCode read_topology_types( CCMIOID& topologyID, std::map< int, int >& cell_topo_types );

    ErrorCode get_int_option( const char* opt_str, EntityHandle seth, Tag& tag, CCMIOID node );

    ErrorCode get_dbl_option( const char* opt_str, EntityHandle seth, Tag& tag, CCMIOID node );

    ErrorCode get_str_option( const char* opt_str,
                              EntityHandle seth,
                              Tag& tag,
                              CCMIOID node,
                              const char* tag_name = NULL );

    //! Cached tags for reading.  Note that all these tags are defined when the
    //! core is initialized.
    Tag mMaterialSetTag;
    Tag mDirichletSetTag;
    Tag mNeumannSetTag;
    Tag mHasMidNodesTag;
    Tag mGlobalIdTag;
    Tag mNameTag;
    Tag mMaterialIdTag, mMaterialTypeTag;
    Tag mRadiationTag, mPorosityIdTag, mSpinIdTag, mGroupIdTag, mColorIdxTag, mProcessorIdTag, mLightMaterialTag,
        mFreeSurfaceMaterialTag;
    Tag mThicknessTag, mProstarRegionNumberTag, mBoundaryTypeTag, mCreatingProgramTag;

    Interface* mbImpl;

    ReadUtilIface* readMeshIface;

    std::map< int, EntityHandle > newMatsets, newNeusets;

    bool hasSolution;
};

}  // namespace moab

#endif
